Skip to content

feat(aparavi): AQL node, multi-tab chat app, auth page removal, reconnect fix#1150

Merged
Rod-Christensen merged 9 commits into
developfrom
feat/aparavi-aql
Jun 9, 2026
Merged

feat(aparavi): AQL node, multi-tab chat app, auth page removal, reconnect fix#1150
Rod-Christensen merged 9 commits into
developfrom
feat/aparavi-aql

Conversation

@Rod-Christensen

@Rod-Christensen Rod-Christensen commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds the Aparavi AQL integration end-to-end and fixes the VSCode auth/reconnect flow.

Aparavi AQL node

  • Queries the Aparavi data governance platform using AQL (Aparavi Query Language)
  • Accepts natural-language questions, generates AQL SELECT statements via the connected LLM, returns file metadata rows
  • Uses @tool_function decorators (current framework pattern), IInvokeLLM.Ask for LLM calls
  • Schema is fixed — no dynamic introspection required
  • Safety: _aql_safe enforces single-statement SELECT-only queries with mutation keyword blocking

Aparavi chat app (aparavi-ui)

  • Multi-tab persistent chat using the Documents library — each tab is an independent chat session backed by a .chat JSON file via the workspace VFS
  • Sidebar with "New Chat" button and chat list
  • Pipeline includes Chat, CrewAI Agent, Aparavi AQL tool, Chart.js tool, and LLM
  • App manifest declares settings for Aparavi server URL, user ID, and password
  • useChatMessages hook extended with initialMessages for restoring saved conversations

Auth page removal & reconnect fix

  • Removed standalone AuthProvider/AuthWebview — the separate sign-in page never actually reconnected after saving new credentials, requiring a VSCode restart
  • Auth failures now open the Settings page focused on the failing group (development/deployment) with an error banner that clears on successful test connection
  • Fixed root reconnect bug: on AuthenticationException, call client.disconnect() to stop the persist:true auto-reconnect loop with stale credentials
  • Works for all connection modes: cloud (OAuth), on-prem (API key), docker, and service

Other

  • Documents.discardDocument() for force-removing documents when backing file is deleted
  • Connection detail modal: added role="dialog", aria-modal, aria-labelledby for accessibility
  • OverviewTab connection rows: keyboard-accessible with tabIndex + onKeyDown
  • Chart.js tool description strengthened so agent always calls it instead of generating configs manually
  • tsconfig target bumped to ES2022 per repo coding guidelines

Original author

Aparavi AQL node originally by @blakewoodaparavi (PR #1147, closed due to fork push limitations). Modernized and extended in this PR.

Test plan

  • ruff check nodes/src/nodes/aparavi_aql/ passes
  • ./builder test — node loads without import errors
  • Connect Aparavi AQL node with LLM in pipeline, run natural-language query, verify rows returned
  • Revoke API key — Settings page opens with error banner, enter new key, test connection (banner clears), save, verify auto-reconnect without restart
  • Multi-tab chat: create tabs, send messages, switch tabs (history preserved), reload (chats restored from disk)
  • Delete a chat from sidebar — tab closes, file removed

Generated with Claude Code

@github-actions github-actions Bot added the module:nodes Python pipeline nodes label Jun 7, 2026
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request introduces an Aparavi AQL node for LLM-driven SQL query generation with safety validation, along with a full-screen Aparavi chat UI app. Supporting infrastructure updates enable app-switching to manage connection monitors and display names. The shared-UI connection details view is refactored from an inline panel to a modal dialog.

Changes

Aparavi AQL Node Implementation

Layer / File(s) Summary
AQL HTTP client and schema foundation
nodes/src/nodes/aparavi_aql/aql_client.py, aql_schema.py
HTTP client for POST query execution and GET validation with timestamp normalization; canonical STORE table schema and LLM prompt formatting.
Global state and client lifecycle
nodes/src/nodes/aparavi_aql/IGlobal.py
Config-driven HTTP client initialization with URL validation; stores optional database description; cleans up on shutdown.
Instance tool functions with LLM integration
nodes/src/nodes/aparavi_aql/IInstance.py
Public tools: get_data (LLM→AQL with safety gates and retries), get_aql (generation only), get_schema (fixed schema); strict prompt construction and Markdown fence stripping.
Package wiring and service configuration
nodes/src/nodes/aparavi_aql/__init__.py, services.json, requirements.txt
Import-time dependency loading; node metadata, LLM invoke requirement, and Aparavi connection parameter configuration.

Aparavi UI App and Supporting Infrastructure

Layer / File(s) Summary
RocketRide client library and connection handler
packages/client-python/src/rocketride/mixins/events.py, packages/client-typescript/src/client/client.ts, packages/ai/src/ai/modules/task/task_conn.py
Adds clearAllMonitors() and identify() client methods; server handler updates connection display name and broadcasts connection events.
Shell and workspace state management
apps/shell-ui/src/workspace/useWorkspaceState.ts, apps/shell-ui/src/lib/Documents.tsx, pnpm-workspace.yaml, apps/shell-ui/src/components/layout/Shell.tsx
App-switching clears monitors and updates connection display; Documents supports non-React subscribers; workspace includes new aparavi-ui app; shell uses fixed client name.
App manifest and rsbuild configuration
apps/aparavi-ui/package.json, rsbuild.config.mts, tsconfig.json
App manifest with metadata and dependencies; Rsbuild config for Module Federation remote building AppDescriptor; .pipe file JSON parsing and TypeScript configuration.
App entry, component, and pipeline definition
apps/aparavi-ui/src/index.ts, AparaviApp.tsx, AppDescriptor.ts, aparavi.pipe, scripts/tasks.js, pipe.d.ts
Dynamic import entry; chat component initializing pipeline via client.use() and managing messages; pipeline wiring chat→agent→AQL tool→return; app module config and TS ambient types.
Connection detail modal and selection behavior
packages/shared-ui/src/modules/server/components/ConnectionsTab.tsx, OverviewTab.tsx
Modal-based connection details replacing inline panel; updated row selection to always select; Escape-key and overlay-click close support; wired into OverviewTab.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChatView as Chat UI
  participant AparaviApp
  participant Pipeline as Aparavi Pipeline
  participant Agent as Aparavi Agent
  participant AQLTool as AQL Tool
  participant LLM
  participant AqlClient
  User->>ChatView: sends question
  ChatView->>AparaviApp: handleSend(text)
  AparaviApp->>Pipeline: sendMessage(client, pipelineToken, text)
  Pipeline->>Agent: invoke with question
  Agent->>AQLTool: get_data(question)
  AQLTool->>LLM: invoke _generate_aql(Question)
  LLM-->>AQLTool: raw AQL string
  AQLTool->>AQLTool: _aql_safe(aql)
  AQLTool->>AqlClient: execute(aql)
  AqlClient-->>AQLTool: {rows, count, aql}
  AQLTool-->>Agent: {rows, aql, count}
  Agent-->>Pipeline: response
  Pipeline-->>ChatView: assistant message
  ChatView-->>User: displays results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

module:nodes, module:ui

Suggested reviewers

  • jmaionchi
  • stepmikhaylov

Poem

🐰 A rabbit hops through code anew,
AQL queries dance on RocketRide's queue,
Modals spring up, monitors shed,
Chat flows smooth from head to head!
Aparavi's here—let's make it fly! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the primary changes: addition of Aparavi AQL node, chat app UI, auth modifications, and reconnect improvements across the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/aparavi-aql

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
🤖 Internal: Discord sync marker

Auto-managed by the Discord notification workflow. Stores the linked Discord message ID. Do not edit or delete.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nodes/src/nodes/aparavi_aql/aql_client.py`:
- Around line 80-95: The code assumes envelope = resp.json() is a dict and calls
envelope.get(...), which raises AttributeError for non-object JSON; update the
response handling in the method that assigns envelope (envelope = resp.json())
to first validate that envelope is an instance of dict (e.g.,
isinstance(envelope, dict)) and if not raise a RuntimeError with a clear message
(e.g., "Aparavi API returned non-object JSON response"), so subsequent accesses
(envelope.get, data = envelope.get('data'), etc.) are safe; adjust any type
hints/comments around envelope/rows/columns accordingly.

In `@nodes/src/nodes/aparavi_aql/aql_schema.py`:
- Around line 223-226: get_schema_dict currently returns the global COLUMNS by
reference, allowing callers to mutate shared state; change get_schema_dict (the
function) so it returns a defensive copy of COLUMNS (e.g., shallow copy via
list(COLUMNS) or a deepcopy if COLUMNS contains nested mutables) in the returned
dict so callers cannot modify the module-level COLUMNS.

In `@nodes/src/nodes/aparavi_aql/IInstance.py`:
- Around line 146-159: The retry loop currently only catches RuntimeError from
client.execute, so failures thrown by _generate_aql (or the LLM it calls) escape
the retry/error path; modify the loop around _generate_aql and subsequent safety
check so generation is inside the try/except (or add a specific try around
_generate_aql) and catch generation/LLM errors, set last_error and previous_aql
appropriately, and continue retries instead of re-raising; ensure the error
response returned after exhausting retries includes the last_error and the last
attempted aql, and apply the same change to the similar block referenced by
_generate_aql at the other location (the block around lines with previous_aql
handling at 324-327).
- Around line 50-63: Replace the unsafe-word blacklist with a strict SELECT-only
allowlist: remove or stop using _UNSAFE_PATTERN and change _aql_safe to validate
the entire AQL string against a single-statement SELECT regex (e.g., ensure it
starts with SELECT, contains no additional statements, and optionally ends with
a single semicolon) using re.IGNORECASE; update any other checks that used
_UNSAFE_PATTERN (including the usage around the other AQL validation at lines
noted in the review) to call the new _aql_safe so only single SELECT statements
are permitted for execution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 24294e0d-b797-4ba5-a3de-712fc77ccf08

📥 Commits

Reviewing files that changed from the base of the PR and between efecb7e and 723a44f.

📒 Files selected for processing (7)
  • nodes/src/nodes/aparavi_aql/IGlobal.py
  • nodes/src/nodes/aparavi_aql/IInstance.py
  • nodes/src/nodes/aparavi_aql/__init__.py
  • nodes/src/nodes/aparavi_aql/aql_client.py
  • nodes/src/nodes/aparavi_aql/aql_schema.py
  • nodes/src/nodes/aparavi_aql/requirements.txt
  • nodes/src/nodes/aparavi_aql/services.json

Comment thread nodes/src/nodes/aparavi_aql/aql_client.py
Comment thread nodes/src/nodes/aparavi_aql/aql_schema.py
Comment thread nodes/src/nodes/aparavi_aql/IInstance.py
Comment thread nodes/src/nodes/aparavi_aql/IInstance.py
Rod-Christensen added a commit that referenced this pull request Jun 8, 2026
- aql_client: guard envelope type before accessing dict fields — non-dict
  JSON responses (list, string) now raise a clear RuntimeError
- aql_schema: return defensive copy of COLUMNS from get_schema_dict() so
  downstream mutation can't alter global state
- IInstance: replace mutation blacklist with SELECT-only allowlist gate —
  query must start with SELECT and contain no unsafe keywords
- IInstance: wrap _generate_aql in try/except inside retry loop so LLM
  generation failures also retry instead of raising immediately

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added builder and removed module:nodes Python pipeline nodes labels Jun 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (4)
nodes/src/nodes/aparavi_aql/aql_schema.py (1)

223-225: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Return a defensive copy of COLUMNS from get_schema_dict().

Line 225 exposes mutable global state by reference, so downstream mutation can corrupt schema output for later calls.

Suggested fix
 def get_schema_dict() -> Dict[str, Any]:
     """Return the structured schema dict for the get_schema tool response."""
-    return {'store': 'STORE', 'columns': COLUMNS}
+    return {'store': 'STORE', 'columns': [col.copy() for col in COLUMNS]}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nodes/src/nodes/aparavi_aql/aql_schema.py` around lines 223 - 225,
get_schema_dict currently returns the global COLUMNS by reference which allows
downstream callers to mutate shared state; update get_schema_dict to return a
defensive copy of COLUMNS (e.g., use copy.deepcopy(COLUMNS) or construct new
dict/list copies) so the returned value cannot modify the module-level COLUMNS;
keep the return shape {'store': 'STORE', 'columns': <copied columns>} and
import/use the copy module if using deepcopy.
nodes/src/nodes/aparavi_aql/aql_client.py (1)

80-93: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard JSON envelope type before dictionary access.

At Line 80, resp.json() can return a non-object JSON value; Line 88 then calls .get(...) and crashes with AttributeError, bypassing your RuntimeError wrapping path.

Suggested fix
             resp.raise_for_status()
             envelope = resp.json()
+            if not isinstance(envelope, dict):
+                raise RuntimeError('Aparavi API returned non-object JSON envelope')
@@
-        data = envelope.get('data') or {}
+        data = envelope.get('data') or {}
+        if not isinstance(data, dict):
+            raise RuntimeError('Aparavi API returned invalid "data" payload')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nodes/src/nodes/aparavi_aql/aql_client.py` around lines 80 - 93, The code
assumes envelope (from resp.json()) is a dict but resp.json() can return
non-dict values; update the handling in the response parsing (around envelope =
resp.json() and subsequent checks) to validate the type before using dict
methods: after envelope = resp.json(), check isinstance(envelope, dict) and if
not raise a RuntimeError (e.g., "Aparavi API returned non-object JSON envelope")
so the existing envelope.get('status'), envelope.get('message'),
envelope.get('data') and data.get('objects') calls are safe; ensure this
validation sits before the if envelope.get('status') != 'OK' block and before
data = envelope.get('data') or {}.
nodes/src/nodes/aparavi_aql/IInstance.py (2)

146-159: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include AQL generation failures in the retry path.

At Line 147, _generate_aql(...) runs outside the try, so LLM/generation exceptions bypass retries and return-shape handling.

Suggested fix
         for _ in range(_MAX_AQL_RETRIES):
-            aql = self._generate_aql(question_text, previous_aql=previous_aql, error=last_error)
-
-            # Safety check — block mutation queries
-            if not _aql_safe(aql):
-                return {'error': 'Generated AQL contains unsafe operations', 'aql': aql, 'rows': []}
-
             try:
+                aql = self._generate_aql(question_text, previous_aql=previous_aql, error=last_error)
+
+                # Safety check — block mutation queries
+                if not _aql_safe(aql):
+                    return {'error': 'Generated AQL contains unsafe operations', 'aql': aql, 'rows': []}
+
                 result = client.execute(aql)
                 return {'rows': result['rows'], 'aql': aql, 'count': result['count']}
-            except RuntimeError as exc:
+            except Exception as exc:
                 last_error = str(exc)
-                previous_aql = aql
+                previous_aql = locals().get('aql', previous_aql)

Also applies to: 324-327

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nodes/src/nodes/aparavi_aql/IInstance.py` around lines 146 - 159, The AQL
generation call _generate_aql is currently outside the try so LLM/generation
exceptions escape the retry loop; wrap the call to _generate_aql inside the same
try/except that handles client.execute so generation errors set last_error
(e.g., str(exc)) and previous_aql as appropriate and allow the loop to continue
for up to _MAX_AQL_RETRIES, then after retries return the consistent error shape
{'error': ..., 'aql': aql_or_none, 'rows': []}; apply the same change to the
other occurrence around lines 324-327 (same function/method where _generate_aql
and _aql_safe are used) so both generation and execution exceptions are retried
and produce the same return structure.

50-63: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce a strict single-statement SELECT allowlist, not only a mutation blacklist.

At Line 60, non-SELECT/multi-statement queries can still pass if they avoid listed keywords. The gate should require one SELECT statement (optional trailing semicolon) and reject additional statements.

Suggested fix
 _UNSAFE_PATTERN = re.compile(
     r'\b(INSERT|UPDATE|DELETE|DROP|TRUNCATE|ALTER|CREATE|EXEC|EXECUTE)\b',
     re.IGNORECASE,
 )
+_SELECT_START = re.compile(r'^\s*SELECT\b', re.IGNORECASE)
@@
 def _aql_safe(aql: str) -> bool:
-    """Return True if the AQL contains no unsafe mutation keywords."""
-    return not _UNSAFE_PATTERN.search(aql)
+    """Allow only a single SELECT statement with no unsafe tokens."""
+    text = aql.strip()
+    if text.endswith(';'):
+        text = text[:-1].rstrip()
+    if ';' in text:
+        return False
+    if not _SELECT_START.match(text):
+        return False
+    return not _UNSAFE_PATTERN.search(text)

Also applies to: 149-151

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nodes/src/nodes/aparavi_aql/IInstance.py` around lines 50 - 63, The current
_aql_safe function uses _UNSAFE_PATTERN to blacklist mutation keywords but must
instead enforce a strict single-statement SELECT allowlist: update _aql_safe to
validate that the input AQL matches exactly one SELECT statement (optionally
with a single trailing semicolon and whitespace) and rejects anything else
(multiple statements, non-SELECT verbs, or embedded semicolons). Locate the
_aql_safe function and replace the blacklist logic with a regex or parser that
enforces: start-of-string, optional whitespace, the word SELECT, any characters,
optional whitespace, optional single semicolon, optional whitespace,
end-of-string; also update any other usage of _aql_safe (e.g., the other
occurrence referencing the same check) so they use the new strict validation and
not the _UNSAFE_PATTERN blacklist.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@nodes/src/nodes/aparavi_aql/aql_client.py`:
- Around line 80-93: The code assumes envelope (from resp.json()) is a dict but
resp.json() can return non-dict values; update the handling in the response
parsing (around envelope = resp.json() and subsequent checks) to validate the
type before using dict methods: after envelope = resp.json(), check
isinstance(envelope, dict) and if not raise a RuntimeError (e.g., "Aparavi API
returned non-object JSON envelope") so the existing envelope.get('status'),
envelope.get('message'), envelope.get('data') and data.get('objects') calls are
safe; ensure this validation sits before the if envelope.get('status') != 'OK'
block and before data = envelope.get('data') or {}.

In `@nodes/src/nodes/aparavi_aql/aql_schema.py`:
- Around line 223-225: get_schema_dict currently returns the global COLUMNS by
reference which allows downstream callers to mutate shared state; update
get_schema_dict to return a defensive copy of COLUMNS (e.g., use
copy.deepcopy(COLUMNS) or construct new dict/list copies) so the returned value
cannot modify the module-level COLUMNS; keep the return shape {'store': 'STORE',
'columns': <copied columns>} and import/use the copy module if using deepcopy.

In `@nodes/src/nodes/aparavi_aql/IInstance.py`:
- Around line 146-159: The AQL generation call _generate_aql is currently
outside the try so LLM/generation exceptions escape the retry loop; wrap the
call to _generate_aql inside the same try/except that handles client.execute so
generation errors set last_error (e.g., str(exc)) and previous_aql as
appropriate and allow the loop to continue for up to _MAX_AQL_RETRIES, then
after retries return the consistent error shape {'error': ..., 'aql':
aql_or_none, 'rows': []}; apply the same change to the other occurrence around
lines 324-327 (same function/method where _generate_aql and _aql_safe are used)
so both generation and execution exceptions are retried and produce the same
return structure.
- Around line 50-63: The current _aql_safe function uses _UNSAFE_PATTERN to
blacklist mutation keywords but must instead enforce a strict single-statement
SELECT allowlist: update _aql_safe to validate that the input AQL matches
exactly one SELECT statement (optionally with a single trailing semicolon and
whitespace) and rejects anything else (multiple statements, non-SELECT verbs, or
embedded semicolons). Locate the _aql_safe function and replace the blacklist
logic with a regex or parser that enforces: start-of-string, optional
whitespace, the word SELECT, any characters, optional whitespace, optional
single semicolon, optional whitespace, end-of-string; also update any other
usage of _aql_safe (e.g., the other occurrence referencing the same check) so
they use the new strict validation and not the _UNSAFE_PATTERN blacklist.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1bf6829e-8764-44aa-8640-03fb691e8cbd

📥 Commits

Reviewing files that changed from the base of the PR and between 723a44f and eae5b66.

📒 Files selected for processing (7)
  • nodes/src/nodes/aparavi_aql/IGlobal.py
  • nodes/src/nodes/aparavi_aql/IInstance.py
  • nodes/src/nodes/aparavi_aql/__init__.py
  • nodes/src/nodes/aparavi_aql/aql_client.py
  • nodes/src/nodes/aparavi_aql/aql_schema.py
  • nodes/src/nodes/aparavi_aql/requirements.txt
  • nodes/src/nodes/aparavi_aql/services.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
nodes/src/nodes/aparavi_aql/aql_schema.py (1)

223-225: ⚠️ Potential issue | 🟡 Minor | 💤 Low value

Shallow copy doesn't protect nested dict mutation.

list(COLUMNS) creates a new list but the dict elements are still shared references. A caller mutating columns[0]['name'] would corrupt global state. Per the previous review suggestion, use a shallow copy of each dict.

Suggested fix
 def get_schema_dict() -> Dict[str, Any]:
     """Return the structured schema dict for the get_schema tool response."""
-    return {'store': 'STORE', 'columns': list(COLUMNS)}
+    return {'store': 'STORE', 'columns': [col.copy() for col in COLUMNS]}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nodes/src/nodes/aparavi_aql/aql_schema.py` around lines 223 - 225,
get_schema_dict currently returns {'store': 'STORE', 'columns': list(COLUMNS)}
which leaves the dict elements in COLUMNS shared; change it to return a new list
of shallow-copied column dicts so callers can't mutate global state (e.g., build
columns as [col.copy() for col in COLUMNS] and return {'store': 'STORE',
'columns': that_list}); update the get_schema_dict function to use this
shallow-copy approach referencing COLUMNS.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/aparavi-ui/tsconfig.json`:
- Around line 3-4: Update the TypeScript target in apps/aparavi-ui/tsconfig.json
from "ES2020" to "ES2022" so it matches the repo's Coderabbit config; locate the
"target" property in that file (alongside the existing "module": "ESNext") and
set its value to "ES2022" (no other changes required).

In `@packages/shared-ui/src/modules/server/components/ConnectionsTab.tsx`:
- Around line 122-130: The modal markup in ConnectionsTab (the div using
commonStyles.modalOverlay and the inner div using styles.modalDialog) lacks
dialog semantics; update the inner modal container to include role="dialog" and
aria-modal="true" and provide an accessible name via aria-labelledby (pointing
to the header span) or aria-label so screen readers announce the dialog; ensure
the close button (onClick={onClose}) remains keyboard-accessible and that the
outer overlay still handles onClick={onClose} while the inner div preserves
e.stopPropagation().

In `@packages/shared-ui/src/modules/server/components/OverviewTab.tsx`:
- Line 451: The table row in OverviewTab.tsx is only clickable via mouse (the
<tr ... onClick={() => setSelectedConnId(conn.id)}> using S.clickableRow), so
make it keyboard-accessible by adding tabIndex={0} and role="button" to the <tr>
and implementing an onKeyDown handler that calls setSelectedConnId(conn.id) when
Enter or Space is pressed (and preventDefault for Space to avoid page scroll),
keeping the existing onClick behavior; this preserves mouse behavior and enables
keyboard users to open the detail modal.

---

Duplicate comments:
In `@nodes/src/nodes/aparavi_aql/aql_schema.py`:
- Around line 223-225: get_schema_dict currently returns {'store': 'STORE',
'columns': list(COLUMNS)} which leaves the dict elements in COLUMNS shared;
change it to return a new list of shallow-copied column dicts so callers can't
mutate global state (e.g., build columns as [col.copy() for col in COLUMNS] and
return {'store': 'STORE', 'columns': that_list}); update the get_schema_dict
function to use this shallow-copy approach referencing COLUMNS.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ddcd4b80-ae40-4cc7-b0fa-d2a2db0f4642

📥 Commits

Reviewing files that changed from the base of the PR and between eae5b66 and 6fa3312.

⛔ Files ignored due to path filters (2)
  • apps/aparavi-ui/src/icon.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (16)
  • apps/aparavi-ui/package.json
  • apps/aparavi-ui/rsbuild.config.mts
  • apps/aparavi-ui/scripts/tasks.js
  • apps/aparavi-ui/src/AparaviApp.tsx
  • apps/aparavi-ui/src/AppDescriptor.ts
  • apps/aparavi-ui/src/aparavi.pipe
  • apps/aparavi-ui/src/index.ts
  • apps/aparavi-ui/src/pipe.d.ts
  • apps/aparavi-ui/tsconfig.json
  • apps/shell-ui/src/components/layout/Shell.tsx
  • nodes/src/nodes/aparavi_aql/IInstance.py
  • nodes/src/nodes/aparavi_aql/aql_client.py
  • nodes/src/nodes/aparavi_aql/aql_schema.py
  • packages/shared-ui/src/modules/server/components/ConnectionsTab.tsx
  • packages/shared-ui/src/modules/server/components/OverviewTab.tsx
  • pnpm-workspace.yaml

Comment thread apps/aparavi-ui/tsconfig.json Outdated
Comment thread packages/shared-ui/src/modules/server/components/ConnectionsTab.tsx
Comment thread packages/shared-ui/src/modules/server/components/OverviewTab.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/shared-ui/package.json (1)

8-62: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore rocketride as a peer dependency to preserve consumer contract.

shared-ui still imports (and in some places re-exports) symbols from rocketride (useChatMessages.ts, types/project.ts, types/shell.ts). Removing rocketride from peerDependencies can break consumers that install shared without explicitly adding rocketride (module/type resolution failures at build/runtime).

Suggested manifest fix
 "peerDependencies": {
+  "rocketride": "workspace:*",
   "remark-gfm": "^4.0.1"
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared-ui/package.json` around lines 8 - 62, The package removed
rocketride from peerDependencies but shared-ui still imports/re-exports types
and hooks from rocketride (see useChatMessages.ts, types/project.ts,
types/shell.ts), which can break downstream consumers; restore rocketride to the
peerDependencies in package.json with the appropriate semver range used by the
monorepo (e.g., match the workspace version or a compatible ^/~ range) so
consumers must provide that package, and update the package.json
"peerDependencies" block to include "rocketride": "<appropriate-version-range>"
to preserve the public contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/shared-ui/package.json`:
- Around line 8-62: The package removed rocketride from peerDependencies but
shared-ui still imports/re-exports types and hooks from rocketride (see
useChatMessages.ts, types/project.ts, types/shell.ts), which can break
downstream consumers; restore rocketride to the peerDependencies in package.json
with the appropriate semver range used by the monorepo (e.g., match the
workspace version or a compatible ^/~ range) so consumers must provide that
package, and update the package.json "peerDependencies" block to include
"rocketride": "<appropriate-version-range>" to preserve the public contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 22ea14b1-e454-47db-8c2d-86ce6163729a

📥 Commits

Reviewing files that changed from the base of the PR and between 6fa3312 and 010abb9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (1)
  • packages/shared-ui/package.json

blakewoodaparavi and others added 6 commits June 8, 2026 16:10
The aparavi_aql node was written ~6 months ago against APIs that have
since been replaced. This commit brings it up to date with the current
rocketlib framework:

1. Tool declaration: Replaced the obsolete ToolsBase abstract class
   (manual _tool_query/_tool_invoke dispatch) with @tool_function
   decorators on IInstance. The framework now auto-discovers tools,
   builds descriptors, and routes invocations — no manual dispatch needed.

2. LLM invocation: Replaced the closure-based pattern
   (getControllerNodeIds + IInvokeLLM(op='ask', ...)) with the current
   self.instance.invoke(IInvokeLLM.Ask(question=q)) API. The framework
   handles routing to the connected LLM node automatically.

3. Deleted aql_driver.py entirely — all business logic (AQL generation,
   retry loop, safety regex) now lives directly on IInstance methods.

4. Simplified IGlobal.py — removed AqlDriver instantiation, kept only
   the AqlClient HTTP client setup which is framework-agnostic.

5. Added docstrings to reach CI coverage threshold.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- aql_client: guard envelope type before accessing dict fields — non-dict
  JSON responses (list, string) now raise a clear RuntimeError
- aql_schema: return defensive copy of COLUMNS from get_schema_dict() so
  downstream mutation can't alter global state
- IInstance: replace mutation blacklist with SELECT-only allowlist gate —
  query must start with SELECT and contain no unsafe keywords
- IInstance: wrap _generate_aql in try/except inside retry loop so LLM
  generation failures also retry instead of raising immediately

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…efactor

- Add aparavi-ui MF remote app: AparaviApp component with embedded
  pipeline, AppDescriptor, rsbuild config, workspace registration
- Shell: set clientName to 'Cloud Shell-UI' instead of first app ID
- ConnectionsTab: refactor layout and connection display
- OverviewTab: minor adjustments

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
shared-ui listed the vscode extension as a peerDependency, creating a
circular dependency cycle (vscode → shared-ui → vscode) that pnpm warned
about on every install. peerDeps are provided by consumers, so shared-ui
should not reference a consuming app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Documents.subscribe

== Problem ==

Cloud Shell-UI connections registered zero server-side monitors, so the
browser-based rocket-ui had no visibility into running tasks. The "Other"
section never appeared, clicking unknown tasks crashed, and switching apps
left orphaned monitor subscriptions on the shared WebSocket connection.

Meanwhile, all Cloud Shell-UI connections showed the same generic name in
the server monitor, making it impossible to tell which app was active.

== Root cause ==

When RocketSidebar replaced the old SidebarPage, the client.addMonitor()
call was dropped. The new component only set up a client-side event
listener without telling the server to route events to this connection.

Additionally, the shell-ui had no mechanism to clean up monitors on app
switch, no way to update the connection display name at runtime, and the
Documents class had no public subscribe API for external listeners.

== Changes ==

Server (task_conn.py):
- Add on_rrext_identify command handler that updates _client_info['name']
  at runtime and broadcasts connection_updated to dashboard subscribers
  so the monitor UI refreshes without polling.

TypeScript SDK (client.ts):
- Add clearAllMonitors(): unsubscribes all tracked monitor keys from the
  server then clears the local ref-count map. Used by shell-ui on app
  switch so the outgoing app's monitors don't leak.
- Add identify(clientName): sends rrext_identify to update this
  connection's display name on the server.

Python SDK (events.py):
- Add clear_all_monitors(): mirror of the TS method.
- Add identify(client_name): mirror of the TS method.

Shell-UI (useWorkspaceState.ts):
- On switchApp, call client.clearAllMonitors() before the new app mounts
  so each app starts with a clean monitor slate.
- On switchApp, call client.identify() with the new app ID so the server
  monitor shows "Cloud Shell-UI — rocketride.pipeBuilder" etc.

Shell-UI (Documents.tsx):
- Add public subscribe(listener) method that returns an unsubscribe
  function. Wraps the private _listeners set so external code (like
  RocketSidebar) can react to document state changes without reaching
  into private internals or misusing the useStore() hook conditionally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rod-Christensen and others added 2 commits June 8, 2026 17:17
… with persistence

Auth page removal & reconnect fix:
- Remove standalone AuthProvider, AuthWebview, and Auth/index.tsx — the
  separate sign-in page was a dead end: after saving new credentials it
  called reconcile() but never actually reconnected, requiring a VSCode
  restart. Instead, auth failures now open the Settings page focused on
  the failing group (development/deployment), which already has test
  connection, full provider selection, and a working save+reconcile flow.
- Add auth error banner to SettingsWebview (red bar at top with the
  failure message, e.g. "Invalid or revoked API key"). The banner clears
  on successful test connection or manual dismiss.
- Fix the root reconnect bug: on AuthenticationException, call
  client.disconnect() to stop the persist:true client's auto-reconnect
  loop. Without this, the SDK client keeps retrying with stale
  credentials in the background, and subsequent connectToEngine() calls
  with fresh credentials fail silently.
- Remove the "API Key cleared successfully" toast — it added noise on
  every auth-failure flow and wasn't useful feedback.
- Update BarStatusProvider AUTH_FAILED click target from auth page to
  settings page.

Aparavi multi-tab chat:
- Rewrite AparaviApp to use Documents library for multi-tab persistent
  chat sessions. Each tab is an independent chat backed by a .chat JSON
  file via the workspace VFS.
- Add AparaviSidebar with "New Chat" button and chat list.
- Add chatStore (VFS read/write/rename/delete helpers) and docs
  (Documents singleton lifecycle).
- Add Documents.discardDocument() for force-removing documents when the
  backing file is deleted from disk.
- Add initialMessages option to useChatMessages hook so restored chats
  can seed the message list from persisted content.
- Add chart_js tool to the Aparavi pipeline and strengthen the tool
  description so the agent always calls it instead of generating configs
  manually.
- Enable status bar in aparavi-ui manifest and add app settings for
  Aparavi server URL, user ID, and password.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- _aql_safe: reject multi-statement queries by checking for embedded
  semicolons after stripping the trailing one. The SELECT-start and
  mutation-keyword checks were already in place but didn't catch
  "SELECT ...; DROP ..." style injection.

- aparavi-ui tsconfig: bump target from ES2020 to ES2022 to match the
  repo's .coderabbit.yaml coding guideline (strict + ES2022 + ESNext).

- ConnectionsTab modal: add role="dialog", aria-modal="true", and
  aria-labelledby so screen readers announce the connection detail
  overlay correctly. Add type="button" on the close button.

- OverviewTab connection rows: add tabIndex={0} and onKeyDown handler
  for Enter/Space so keyboard users can open the connection detail
  modal, not just mouse users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Rod-Christensen Rod-Christensen changed the title feat(nodes): add aparavi aql feat(aparavi): AQL node, multi-tab chat app, auth page removal, reconnect fix Jun 9, 2026
@Rod-Christensen Rod-Christensen requested a review from Copilot June 9, 2026 00:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an end-to-end Aparavi AQL integration (node + chat UI app) and simplifies the VSCode auth recovery flow by routing auth failures to Settings, while also improving shell/server monitoring behavior and a few UI accessibility details.

Changes:

  • Introduces a new aparavi_aql tool node (AQL generation + execution + schema context + safety checks) and wires it into an aparavi-ui multi-tab persistent chat app/pipeline.
  • Removes the standalone VSCode auth page/provider; auth failures now open Settings (focused section + banner), and reconnect behavior is corrected by disconnecting on auth errors.
  • Adds monitor-management/identify APIs across clients and server, plus UI tweaks (connection detail modal + keyboard-accessible rows) and Documents utilities.

Reviewed changes

Copilot reviewed 39 out of 42 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pnpm-workspace.yaml Adds apps/aparavi-ui to the workspace.
pnpm-lock.yaml Adds dependency entries for apps/aparavi-ui.
packages/shared-ui/src/modules/server/components/OverviewTab.tsx Makes connection rows keyboard-activatable and opens a connection detail modal.
packages/shared-ui/src/modules/server/components/ConnectionsTab.tsx Refactors connection details into a reusable modal with dialog ARIA attributes.
packages/shared-ui/src/modules/chat/types.ts Adds initialMessages option for restoring chat history.
packages/shared-ui/src/modules/chat/hooks/useChatMessages.ts Seeds chat state from initialMessages.
packages/client-typescript/src/client/client.ts Adds clearAllMonitors() and identify() APIs to the TS client.
packages/client-python/src/rocketride/mixins/events.py Adds clear_all_monitors() and identify() APIs to the Python client.
packages/ai/src/ai/modules/task/task_conn.py Implements rrext_identify server handler and broadcasts dashboard update events.
nodes/src/nodes/tool_chartjs/IInstance.py Strengthens the Chart.js tool description to encourage tool usage.
nodes/src/nodes/aparavi_aql/services.json Declares the new Aparavi AQL node service + config fields.
nodes/src/nodes/aparavi_aql/requirements.txt Declares no extra Python deps for the node.
nodes/src/nodes/aparavi_aql/IInstance.py Implements AQL generation/execution tools with safety checks and retries.
nodes/src/nodes/aparavi_aql/IGlobal.py Initializes the Aparavi AQL HTTP client from node config.
nodes/src/nodes/aparavi_aql/aql_schema.py Adds fixed STORE schema and prompt text for LLM context.
nodes/src/nodes/aparavi_aql/aql_client.py Implements REST client for executing/validating AQL queries.
nodes/src/nodes/aparavi_aql/init.py Node module bootstrap + dependency loading.
apps/vscode/src/providers/views/Settings/SettingsWebview.tsx Adds an auth-failure banner and clears it on successful connection test.
apps/vscode/src/providers/views/Auth/AuthWebview.tsx Removes the standalone auth recovery webview.
apps/vscode/src/providers/shared/connection-message-handler.ts Updates doc comment to reflect removal of AuthProvider usage.
apps/vscode/src/providers/SettingsProvider.ts Extends settings open command to accept an auth error banner message.
apps/vscode/src/providers/BarStatusProvider.ts Routes auth-failed status bar action to Settings page.
apps/vscode/src/providers/AuthProvider.ts Removes the standalone AuthProvider implementation.
apps/vscode/src/extension.ts Stops registering AuthProvider.
apps/vscode/src/connection/connection.ts Disconnects client on auth failure and opens Settings (focused + error).
apps/vscode/rsbuild.config.mjs Removes the page-auth entry point from the VSCode webview build.
apps/shell-ui/src/workspace/useWorkspaceState.ts Clears monitors + updates connection identity when switching apps.
apps/shell-ui/src/lib/Documents.tsx Adds subscribe() and discardDocument() to support UI + deletion flows.
apps/shell-ui/src/components/layout/Shell.tsx Sets a stable base clientName (“Cloud Shell-UI”).
apps/aparavi-ui/tsconfig.json Adds aparavi-ui TS config targeting ES2022.
apps/aparavi-ui/src/pipe.d.ts Enables importing .pipe files as JSON modules.
apps/aparavi-ui/src/index.ts Switches to async boundary entry and loads the AppDescriptor.
apps/aparavi-ui/src/icon.svg Adds app icon.
apps/aparavi-ui/src/docs.ts Adds shared Documents singleton management for the app.
apps/aparavi-ui/src/chatStore.ts Adds .chat file I/O helpers under .chats/.
apps/aparavi-ui/src/AppDescriptor.ts Defines the Module Federation AppDescriptor for aparavi-ui.
apps/aparavi-ui/src/AparaviSidebar.tsx Implements chat sidebar with Explorer-based chat file management.
apps/aparavi-ui/src/AparaviApp.tsx Implements multi-tab chat UI, pipeline startup, and chat persistence logic.
apps/aparavi-ui/src/aparavi.pipe Adds the pipeline that wires chat → agent → aparavi_aql tool → answers (+ chart tool).
apps/aparavi-ui/scripts/tasks.js Adds builder module tasks config for aparavi-ui.
apps/aparavi-ui/rsbuild.config.mts Adds RSBuild config for aparavi-ui as an MF remote.
apps/aparavi-ui/package.json Adds app manifest + build dependencies for aparavi-ui.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/shell-ui/src/workspace/useWorkspaceState.ts
Comment thread apps/aparavi-ui/src/AparaviApp.tsx Outdated
Comment thread apps/aparavi-ui/src/AparaviSidebar.tsx
Comment thread apps/aparavi-ui/src/AparaviSidebar.tsx
- Await clearAllMonitors() in switchApp to prevent monitor race on app switch
- Debounce-write chat messages to disk via saveChat() after updateContent()
- Replace vfs={null as any} with typed NOOP_VFS stub in AparaviSidebar
- Add allowFolders config to ExplorerConfig; chat sidebar sets false to hide
  the "New Folder" button for flat .chat file lists

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Rod-Christensen

Copy link
Copy Markdown
Collaborator Author

Passed with exception of Mac which got a network error downloading torch

@Rod-Christensen Rod-Christensen merged commit 89b1545 into develop Jun 9, 2026
17 checks passed
@Rod-Christensen Rod-Christensen deleted the feat/aparavi-aql branch June 9, 2026 01:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants